package com.huidu.bitrade.controller;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.huidu.bitrade.constant.WithdrawStatus;
import com.huidu.bitrade.entity.Coin;
import com.huidu.bitrade.entity.Member;
import com.huidu.bitrade.entity.MemberWallet;
import com.huidu.bitrade.entity.WithdrawRecord;
import com.huidu.bitrade.service.*;
import com.huidu.bitrade.util.MessageResult;
import com.huidu.bitrade.vendor.provider.SMSProvider;
import com.spark.bipay.entity.Trade;
import com.spark.bipay.http.client.BiPayClient;
import com.spark.bipay.utils.HttpUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;

@RestController
@RequestMapping("wallet")
@AllArgsConstructor
@Slf4j
public class CallbackController {

    private final BiPayClient biPayClient;
    private final BiPayService biPayService;
    private final MemberWalletService walletService;
    private final WithdrawRecordService withdrawRecordService;
    private final CoinService coinService;
    private final MemberService memberService;
    private final SMSProvider smsProvider;

    @RequestMapping("/bipay/notify")
    public synchronized String tradeCallback(@RequestParam(value = "timestamp",defaultValue = "") String timestamp,
                                             @RequestParam(value = "nonce",defaultValue = "") String nonce,
                                             @RequestParam(value ="body",defaultValue = "") String body,
                                             @RequestParam(value ="sign",defaultValue = "") String sign) throws Exception {
        if (Strings.isNullOrEmpty(timestamp)||Strings.isNullOrEmpty(nonce)||Strings.isNullOrEmpty(body)||Strings.isNullOrEmpty(sign)){
            log.info("empty timestamp:{},nonce:{},sign:{},body:{}", timestamp, nonce, sign, body);
            return "error";
        }
        log.info("timestamp:{},nonce:{},sign:{},body:{}", timestamp, nonce, sign, body);
        if (!HttpUtil.checkSign(biPayClient.getMerchantKey(), timestamp, nonce, body, sign)) {
            return "error";
        }
        Trade trade = JSONObject.parseObject(body,Trade.class);
        log.info("trade:{}",trade);
        if(trade.getTradeType() == 1){
            recharge(body, trade);
        } else if (trade.getTradeType() == 2) {
            String error = withdraw(trade);
            if (error != null) return error;
        }
        return "success";
    }

    private String withdraw(Trade trade) {
        log.info("=====收到提币处理通知=====");
        log.info("address:{},amount:{},coinType:{},businessId:{}", trade.getAddress(), trade.getAmount(), trade.getCoinType(), trade.getBusinessId());
        Long withdrawId = Long.parseLong(trade.getBusinessId());
        WithdrawRecord withdrawRecord = withdrawRecordService.findOne(withdrawId);
        if (withdrawRecord == null) {
            return "error";
        }
        //转账失败，状态变回等待放币
        if(trade.getStatus() == 1){
            log.info("审核通过，转账中");
            //TODO: 提币交易已发出，理提币订单状态，扣除提币资金
            if(withdrawRecord.getStatus() == WithdrawStatus.FAIL || withdrawRecord.getStatus() == WithdrawStatus.SUCCESS){
                return "error";
            }
            //审核通过
//                withdrawRecordService.withdrawSuccess(withdrawId, txid);
        } else if (trade.getStatus() == 2) {
            log.info("审核不通过");
            //TODO: 处理提币订单状态，订单号为 businessId
            if(withdrawRecord.getStatus() == WithdrawStatus.FAIL || withdrawRecord.getStatus() == WithdrawStatus.SUCCESS){
                return "error";
            }
            withdrawRecordService.withdrawFail(withdrawId);
        } else if (trade.getStatus() == 3) {
            log.info("提币已到账,txId：{}", trade.getTxId());
            //TODO: 提币已到账，可以向提币用户发出通知
            withdrawRecordService.withdrawSuccess(withdrawId, trade.getTxId());
        }
        return null;
    }

    private void recharge(String body, Trade trade) {
        log.info("=====收到充币通知======");
        log.info("address:{},amount:{},coinType:{},fee:{}", trade.getAddress(), trade.getAmount(), trade.getCoinType(), trade.getFee());
        //金额为最小单位，需要转换,包括amount和fee字段
        BigDecimal amount = trade.getAmount().divide(BigDecimal.TEN.pow(trade.getDecimals()),8, RoundingMode.DOWN);
        BigDecimal fee = trade.getFee().divide(BigDecimal.TEN.pow(trade.getDecimals()),8, RoundingMode.DOWN);
        log.info("amount={},fee={}",amount.toPlainString(),fee.toPlainString());

        String txId= trade.getTxId();
        String address = trade.getAddress();
        String unit = biPayService.code2Coin(trade);
        Coin coin = coinService.findByUnit(unit);
        log.info("=======充值unit======{}",unit);
        log.info("=======查询数据库对应coin======{}",coin);
        if (coin != null && walletService.findDeposit(address, txId) == null ) {
            //&& amount.compareTo(coin.getMinRechargeAmount()) >= 0
            log.info("=========调用充值service======coin:{},address:{},amount:{},txId:{}",coin,address,amount,txId);
            MessageResult mr = walletService.recharge(coin, address, amount, txId);
            log.info("wallet recharge result:{}", mr);
            if(mr.getCode()==0){
                MemberWallet wallet = walletService.findByCoinAndAddress(coin, address);
                Member mRes = memberService.findOne(wallet.getMemberId());
                try {
                    log.info("========开始发送短信======={}",mRes);
                    smsProvider.sendMessageByTempId(mRes.getMobilePhone(), Collections.singletonList("充值" + wallet.getCoin().getUnit() + "成功.充值数量为:" + amount.stripTrailingZeros().toPlainString()),2);
                } catch (Exception e) {
                    log.info("========发送短信异常======={}",mRes,e);
                }
            }
        }else {
            log.warn("未能入账{}" ,body);
        }
    }
}
